package com.bootx.predict;

import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.predict.pojo.PredictionResult;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.RedPacketRecord;
import com.bootx.predict.util.PredictUtils;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author black
 * 指数平滑策略 (Exponential Smoothing Strategy)
 */
@Component("exponentialSmoothingPredict")
public class ExponentialSmoothingPredict extends PredictPlugin {

    /**
     * α 控制衰减，取值范围 (0,1)，一般 0.3 ~ 0.7。
     */
    private final double alpha = 0.4;

    @Override
    public String getName() {
        return "exponentialSmoothingPredict";
    }

    @Override
    public List<PredictionResult> predict(List<RedPacketBatch> list, Set<Integer> indexes) {
        List<RedPacketRecord> history = PredictUtils.parseData(list);
        // 按 index 分组
        Map<Integer, List<Boolean>> stateMap = new HashMap<>();
        Map<Integer, List<Integer>> timeMap = new HashMap<>();
        for (RedPacketRecord r : history) {
            stateMap.computeIfAbsent(r.getIndex(), k -> new ArrayList<>())
                    .add(PredictUtils.isAmountOdd(r.getAmount()));
            timeMap.computeIfAbsent(r.getIndex(), k -> new ArrayList<>())
                    .add(r.getOpenTime());
        }

        List<PredictionResult> results = new ArrayList<>();
        for (int idx : indexes) {
            List<Boolean> states = stateMap.getOrDefault(idx, Collections.emptyList());
            int total = states.size();
            int oddCount = (int) states.stream().filter(b -> b).count();

            double avgOpenTime = timeMap.getOrDefault(idx, Collections.emptyList())
                    .stream().mapToInt(Integer::intValue).average().orElse(0);

            double probability = 0.5;
            if (!states.isEmpty()) {
                probability = computeExponentialSmoothing(states, alpha);
            }

            results.add(new PredictionResult(idx, total, oddCount, probability, Double.valueOf(avgOpenTime+"").intValue()));
        }

        return results;
    }

    private double computeExponentialSmoothing(List<Boolean> states, double alpha) {
        double smoothed = 0.5; // 初始值
        for (boolean state : states) {
            double value = state ? 1.0 : 0.0;
            smoothed = alpha * value + (1 - alpha) * smoothed;
        }
        return smoothed;
    }
}
